Skip to content

fix(ui): fix focusing bugs while editing files#4197

Merged
TheodoreSpeaks merged 1 commit intostagingfrom
fix/md-edit-skips
Apr 16, 2026
Merged

fix(ui): fix focusing bugs while editing files#4197
TheodoreSpeaks merged 1 commit intostagingfrom
fix/md-edit-skips

Conversation

@TheodoreSpeaks
Copy link
Copy Markdown
Collaborator

Summary

We have some issues with refocused views while editing.

  1. Stream completion refocuses on the chat
  2. Network drops causes the chat to rerender and cursor to appear at the bottom.

Added guards to ensure that if file view is focused that we don't mess with cursor location.

Type of Change

  • Bug fix
  • New feature
  • Breaking change
  • Documentation
  • Other: ___________

Testing

  • Tested locally. Hard to repro issue 2, but will push and check to see if i can still repro.

Checklist

  • Code follows project style guidelines
  • Self-reviewed my changes
  • Tests added/updated and passing
  • No new warnings introduced
  • I confirm that I have read and agree to the terms outlined in the Contributor License Agreement (CLA)

Screenshots/Videos

@vercel
Copy link
Copy Markdown

vercel bot commented Apr 16, 2026

The latest updates on your projects. Learn more about Vercel for GitHub.

1 Skipped Deployment
Project Deployment Actions Updated (UTC)
docs Skipped Skipped Apr 16, 2026 5:32pm

Request Review

@cursor
Copy link
Copy Markdown

cursor bot commented Apr 16, 2026

PR Summary

Medium Risk
Touches focus management and DOM measurement/resize observers in core editing UI, which can cause subtle regressions (cursor jumps, performance, or missed auto-scroll) if edge cases weren’t covered.

Overview
Reduces UI focus/scroll disruptions during streaming and transient reloads.

In file-viewer.tsx, switches code-editor line-number/visual-line calculations to use refs (renderedContentRef, calculateVisualLinesRef) so event handlers/ResizeObserver don’t thrash on content changes, and only shows the “Failed to load file content” empty-state when an initial fetch fails (error && !isInitialized).

In user-input.tsx, guards the auto-focus behavior after send completion and on mount so the chat textarea won’t steal focus if the user is already editing another input/textarea. generic-resource-content.tsx also changes auto-scroll-to-bottom to directly scroll the parent container to its end instead of scrollIntoView.

Reviewed by Cursor Bugbot for commit d2bb494. Bugbot is set up for automated code reviews on this repo. Configure here.

@greptile-apps
Copy link
Copy Markdown
Contributor

greptile-apps bot commented Apr 16, 2026

Greptile Summary

This PR fixes two focus-related bugs in the file editor: stream completion stealing focus from an active file editor, and network-triggered re-renders moving the cursor in the chat input. The fix adds isEditingElsewhere guards in user-input.tsx, refactors file-viewer.tsx's visual-line calculation to the ref-callback pattern (avoiding stale closures and unnecessary effect re-runs), and tightens the error-display guard so a transient fetch failure during an editing session no longer replaces the file view with an error screen.

Confidence Score: 5/5

Safe to merge — all changes are targeted defensive guards with no new logic paths that could break existing behaviour.

All findings are P2 or lower. The focus guards are narrowly scoped, the ref-callback refactor is a well-established React pattern, and the error-condition tightening is logically sound. No regressions identified.

No files require special attention.

Important Files Changed

Filename Overview
apps/sim/app/workspace/[workspaceId]/home/components/user-input/user-input.tsx Adds isEditingElsewhere guard before auto-focusing the chat textarea — prevents focus theft from file editor textareas on stream completion and re-renders.
apps/sim/app/workspace/[workspaceId]/files/components/file-viewer/file-viewer.tsx Refactors visual-line calculation to the ref-callback pattern so the ResizeObserver effect is stable; splits effects to avoid re-registering event listeners on content change; narrows error display to only !isInitialized to prevent error-screen flash during editing on network drops.
apps/sim/app/workspace/[workspaceId]/home/components/mothership-view/components/resource-content/generic-resource-content.tsx Replaces scrollIntoView({ behavior: 'smooth' }) with direct scrollTop = scrollHeight on the container, avoiding implicit focus side effects from the smooth-scroll path.

Sequence Diagram

sequenceDiagram
    participant Stream as Streaming engine
    participant UI as UserInput (chat)
    participant RAF as requestAnimationFrame
    participant Active as document.activeElement
    participant FV as FileViewer textarea

    Note over FV: User is editing a file
    Stream->>UI: isSending → false (stream done)
    UI->>Active: check document.activeElement
    Active-->>UI: HTMLTextAreaElement (FileViewer)
    UI->>UI: isEditingElsewhere = true
    UI->>UI: skip focus() — no cursor theft

    Note over FV: User NOT editing
    Stream->>UI: isSending → false (stream done)
    UI->>Active: check document.activeElement
    Active-->>UI: body / other element
    UI->>UI: isEditingElsewhere = false
    UI->>RAF: requestAnimationFrame → focus chat textarea
Loading

Reviews (1): Last reviewed commit: "fix(ui): fix focusing bugs while editing..." | Re-trigger Greptile

Comment on lines +400 to 406
const active = document.activeElement
const isEditingElsewhere =
active instanceof HTMLTextAreaElement || active instanceof HTMLInputElement
if (!isEditingElsewhere) {
textareaRef.current?.focus()
}
}
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 contenteditable elements not covered by focus guard

The guard checks HTMLTextAreaElement | HTMLInputElement, but won't catch contenteditable divs (e.g. rich-text editors, ProseMirror, etc.). Currently fine since the file editor uses a <textarea>, but worth expanding if any future editor component uses contenteditable.

Suggested change
const active = document.activeElement
const isEditingElsewhere =
active instanceof HTMLTextAreaElement || active instanceof HTMLInputElement
if (!isEditingElsewhere) {
textareaRef.current?.focus()
}
}
const isEditingElsewhere =
active instanceof HTMLTextAreaElement ||
active instanceof HTMLInputElement ||
(active instanceof HTMLElement && active.isContentEditable)

The same pattern applies to the second effect (initial mount focus) below.

@TheodoreSpeaks TheodoreSpeaks merged commit 4cdc941 into staging Apr 16, 2026
14 checks passed
@waleedlatif1 waleedlatif1 deleted the fix/md-edit-skips branch April 16, 2026 20:05
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant